package com.itheima.restkeeper.face;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.kernel.Config;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.restkeeper.TradingSettingFace;
import com.itheima.restkeeper.constant.TradingCacheConstant;
import com.itheima.restkeeper.enums.TradingSettingEnum;
import com.itheima.restkeeper.exception.ProjectException;
import com.itheima.restkeeper.mapper.PayconfigMapper;
import com.itheima.restkeeper.pojo.PaySetting;
import com.itheima.restkeeper.pojo.Payconfig;
import com.itheima.restkeeper.pojo.Payconfigvalue;
import com.itheima.restkeeper.pojo.TradingSetting;
import com.itheima.restkeeper.req.TradingSettingVo;
import com.itheima.restkeeper.service.IPayconfigService;
import com.itheima.restkeeper.service.IPayconfigvalueService;
import com.itheima.restkeeper.service.ITradingSettingService;
import com.itheima.restkeeper.utils.BeanConv;
import com.itheima.restkeeper.utils.EmptyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Method;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName TradingSettingFaceImpl.java
 * @Description 企业配置
 */
@Slf4j
@DubboService(version = "${dubbo.application.version}", timeout = 5000,
        methods = {
                @Method(name = "findTradingSettingVoPage", retries = 2),
                @Method(name = "createTradingSetting", retries = 0),
                @Method(name = "updateTradingSetting", retries = 0),
                @Method(name = "deleteTradingSetting", retries = 0),
                @Method(name = "saveOrUpdateTradingSetting", retries = 0),
                @Method(name = "findTradingSettingByEnterpriseId", retries = 2)

        })
public class TradingSettingFaceImpl implements TradingSettingFace {

    @Autowired
    ITradingSettingService tradingSettingService;

    @Autowired
    IPayconfigService payconfigService;

    @Autowired
    IPayconfigvalueService payconfigvalueService;

    @Autowired
    RedissonClient redissonClient;

    // value： 存储的key的前缀
    // key: redis key, 整体的key=  value + key
    // 完整key: tradingSettingPage:page_1:size_104738274382432
    //redis的value值：pageVo--> JSON
    @Override
    @Cacheable(value = "tradingSettingPage",key = "'page_'+#pageNum+':size_'+#pageSize+#enterpriseSettingVo.hashCode()")
    public Page<TradingSettingVo> findTradingSettingVoPage(TradingSettingVo enterpriseSettingVo, int pageNum, int pageSize) {
        Page<TradingSetting> page = tradingSettingService.findTradingSettingVoPage(enterpriseSettingVo, pageNum, pageSize);
        Page<TradingSettingVo> pageVo = new Page<>();
        BeanConv.toBean(page, pageVo);
        //结果集转换
        List<TradingSetting> enterpriseList = page.getRecords();
        List<TradingSettingVo> enterpriseVoList = BeanConv.toBeanList(enterpriseList, TradingSettingVo.class);
        pageVo.setRecords(enterpriseVoList);
        return pageVo;
    }

    @Override
    public TradingSettingVo createTradingSetting(TradingSettingVo enterpriseSettingVo) {
        return BeanConv.toBean(tradingSettingService.createTradingSetting(enterpriseSettingVo), TradingSettingVo.class);
    }

    @Override
    public Boolean updateTradingSetting(TradingSettingVo enterpriseSettingVo) {
        return tradingSettingService.updateTradingSetting(enterpriseSettingVo);
    }

    @Override
    public Boolean deleteTradingSetting(String[] checkedIds) {
        return tradingSettingService.deleteTradingSetting(checkedIds);
    }

    /**
     * tradingSettingVo --> Payconfig 和 Payconfigvalue对象
     * @param tradingSettingVo
     * @return
     */
    @Override
    public TradingSettingVo saveOrUpdateTradingSetting(TradingSettingVo tradingSettingVo) {

        //1 对象装换成map（获取对象中的属性名称和对应的值）
        Map<String, String> map = JSON.parseObject(JSON.toJSONString(tradingSettingVo), Map.class);

        //2 遍历map，封装到Payconfig和Payconfigvalue对象
        for (Map.Entry<String, String> entry : map.entrySet()) {

            //如果key是type和enterpriseId 跳过本次循环
            if (entry.getKey().equals("type") || entry.getKey().equals("enableFlag") || entry.getKey().equals("enterpriseId")) {
                continue;
            }

            //3 查询Payconfig是否存在，如果存在则直接获取对应的id，如果不存在则新增主键返回
            boolean b = false;
            Payconfig payconfig= payconfigService.getOne(Wrappers.<Payconfig>lambdaQuery()
                    .eq(Payconfig::getPayKey, entry.getKey())
                    .eq(Payconfig::getType, tradingSettingVo.getType())
            );
            if (payconfig == null || payconfig.getId() == null) {
                payconfig = Payconfig.builder()
                    .payKey(entry.getKey())
                    .type(tradingSettingVo.getType())
                    .build();
                b = payconfigService.saveOrUpdate(payconfig);
                if (!b) throw new ProjectException(TradingSettingEnum.CREATE_FAIL);
            }

            //4 删除原有配置，在新增
            payconfigvalueService.remove(Wrappers.<Payconfigvalue>lambdaQuery()
                    .eq(Payconfigvalue::getPayconfigId, payconfig.getId())
                    .eq(Payconfigvalue::getEnterpriseId,tradingSettingVo.getEnterpriseId() )
            );

            //5 新增新的支付配置值
            Payconfigvalue payconfigvalue = Payconfigvalue.builder()
                    .enterpriseId(tradingSettingVo.getEnterpriseId())
                    .payconfigId(payconfig.getId())
                    .payValue(String.valueOf(entry.getValue()))
                    .build();
            b = payconfigvalueService.save(payconfigvalue);
            if (!b) throw new ProjectException(TradingSettingEnum.CREATE_FAIL);

        }

        //保存到Redis
        createOrUpdateConfigToRedis(tradingSettingVo);

        return tradingSettingVo;
    }

    @Override
    public TradingSettingVo findTradingSettingByEnterpriseId() {

        TradingSetting tradingSetting = tradingSettingService.getOne(new QueryWrapper<>());
        return BeanConv.toBean(tradingSetting, TradingSettingVo.class);
    }

    @Autowired
    PayconfigMapper payconfigMapper;

    /***
     * @description 查询当前企业的交易配置
     * @return
     * @return: TradingSettingVo
     * @param tradingSettingVo
     */
    @Override
    public TradingSettingVo findTradingSettingByEnterpriseId(TradingSettingVo tradingSettingVo) {

        //1 从redis中获取对应的支付配置 type=1 支付宝  type=2 微信
        Integer type = tradingSettingVo.getType();
        Long enterpriseId = tradingSettingVo.getEnterpriseId();
        String key =
                TradingCacheConstant.REDIS_GROUP+type+":"+enterpriseId;
        RBucket<TradingSettingVo> bucket = redissonClient.getBucket(key);
        TradingSettingVo settingVo = bucket.get();
        //2 redis中存在则直接返回给前端
        if (!EmptyUtil.isNullOrEmpty(settingVo)) {
            return settingVo;
        }

        //3 不存在则到数据库查询PaySetting对象， 目的：获取TradingSettingVo对象
        //思路：List<PaySetting>  转换成TradingSettingVo对象
        List<PaySetting> paySettings = payconfigMapper.queryAllPayconfig(tradingSettingVo.getEnterpriseId(), tradingSettingVo.getType());
        Map map = new HashMap();
        //3.1 遍历集合数据转换成map {"wxpayappid":"1111", "wxpaymucid":"2222"}
        for (PaySetting paySetting : paySettings) {
            map.put(paySetting.getPayKey(), paySetting.getPayValue());
        }
        //3.2 map转换成json，方便json转成对象
        String jsonString = JSON.toJSONString(map);
        //3.3 fastjson json字符串转换成 TradingSettingVo对象（json中key和TradingSettingVo成员属性保持一致）
        tradingSettingVo = JSON.parseObject(jsonString, TradingSettingVo.class);

        //4 封装填充tradingSettingVo类型和企业号
        tradingSettingVo.setType(type);
        tradingSettingVo.setEnterpriseId(enterpriseId);

        //5 保持到redis
        createOrUpdateConfigToRedis(tradingSettingVo);

        //6 返回结果
        return tradingSettingVo;
    }

    /***
     * @description 初始化或更新配置进入redis
     * @param tradingSettingVo 配置信息
     * @return
     */
    private void createOrUpdateConfigToRedis(TradingSettingVo tradingSettingVo){
        String key = TradingCacheConstant.REDIS_GROUP+tradingSettingVo.getType()+":"+tradingSettingVo.getEnterpriseId();
        RBucket<TradingSettingVo> bucket = redissonClient.getBucket(key);
        bucket.set(tradingSettingVo);
    }

    /***
     * @description 从redis中删除配置信息
     * @param tradingSetting 配置信息
     * @return
     */
    public void removeConfigToRedis(TradingSetting tradingSetting){
        //2.5、配置信息从redis中移除
        String key = TradingCacheConstant.ALI_PAY + tradingSetting.getEnterpriseId();
        RBucket<Config> bucket = redissonClient.getBucket(key);
        bucket.delete();
    }
}
